package bugzillapreprocessor.view;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import bugzillapreprocessor.adaptor.DateAdaptor;
import bugzillapreprocessor.adaptor.PrinterAdapter;
import bugzillapreprocessor.model.Issue;

/**
 * The class which produces the issue-dependencies.txt file
 */
public class YearlyView implements Views { 

	private final String filename = "yearlyview.txt";
	private ArrayList<Issue> issues;

	/**
	 * Process the issue objects for additional data and for printing
	 */
	public void processData(ArrayList<Issue> issues) {
		this.issues = issues;
		if (issues.size() > 0) {
			printToFile(convertToString());
		} else {
			printToFile("");
		}
	}

	/**
	 * Print the processed data to a file
	 * 
	 * @param msg
	 *            The data to print to file
	 */
	private void printToFile(String msg) {
		PrinterAdapter.print(filename, msg);
	}

	/**
	 * Convert the issue data to a string which will be output to file
	 * 
	 * @return The String representation of the data for all issues
	 */
	@SuppressWarnings("rawtypes")
	private String convertToString() {
		
        StringBuilder sb = new StringBuilder();
        YearlyViewData dat;
        String ls = System.getProperty("line.separator");
        Iterator<Issue> it = issues.iterator();
        Map<Integer, YearlyViewData> map = new HashMap<Integer, YearlyViewData>();

        while(it.hasNext()) {
            Issue i = (Issue) it.next();

            String deltaTs = i.getDelta_ts();
            String creationTs = i.getCreation_ts();
            
            int yearStart = getYear(creationTs);
            int yearClose = getYear(deltaTs);

			Boolean fixedAndClosed = i.getResolution()
					.equalsIgnoreCase("Fixed") == true
					&& i.getIssueStatus().equalsIgnoreCase("Closed") == true;

            for (int j=yearStart; j<=yearClose; j++) {
            	String d1 = j+"-01-01 00:00:00";
            	String d2 = j+"-12-31 23:59:59";

            	dat = map.get(j);
                if (dat == null)
                {
                	dat = new YearlyViewData();
                	map.put(j, dat);
                	// Calculate absolute days here
                	dat.absoluteDays = (getDaysOpen(d2, "2000-01-01") + 1);
                }

            	if (j == yearStart){
            		dat.newIssues++;
            		if (fixedAndClosed) {
            			dat.daysOpen += getDaysOpen(d2, creationTs);
            		}
            	}
            	else if (j == yearClose){
            		dat.closedIssues++;
            		if (fixedAndClosed) {
            			dat.daysOpen += getDaysOpen(deltaTs, d1);
            		}
            	}
            	else {
            		if (fixedAndClosed){
            			dat.daysOpen += (getDaysOpen(d2, d1) + 1);
            		}
            	}

        		if (fixedAndClosed){
                	dat.totalFixedAndClosedIssues++;
        		}
            }
        }

        Iterator<Entry<Integer, YearlyViewData>> itr = map.entrySet().iterator();
        while (itr.hasNext()) {

			Map.Entry pair = (Map.Entry)itr.next();
            itr.remove(); // avoids a ConcurrentModificationException
            dat = (YearlyViewData) pair.getValue();
            
            Number avgDays = 0;
            
            if (dat.totalFixedAndClosedIssues > 0) {
            	avgDays = dat.daysOpen / dat.totalFixedAndClosedIssues;
            }
            
            sb.append("-------------------------New Year-------------------").append(ls);
        	sb.append("Year: ").append(pair.getKey()).append(ls);
            sb.append("Absolute_days: ").append(dat.absoluteDays).append(ls);
        	sb.append("Total number of new issues: ").append(dat.newIssues).append(ls);
        	sb.append("Total number of closed issues: ").append(dat.closedIssues).append(ls);
        	sb.append("Average_days_open: ").append(avgDays).append(ls);
            sb.append("-------------------------Year End--------------------").append(ls);
        }
        return sb.toString();
    }

	/**
	 * Get the number of days from the given date1 to given date2
	 * 
	 * @param date1
	 *            From date
	 * @param date2
	 *            To date
	 * @return The number of day between date1 and date2
	 */
	private long getDaysOpen(String date1, String date2) {
		return DateAdaptor.getDays(date1, date2);
	}

	/**
	 * Get the year from the given date string
	 * @param date The date to parse
	 * @return The year number in the format yyyy
	 */
	private int getYear(String date) {
		return Integer.parseInt(DateAdaptor.getYear(date));
	}

	/**
	 * A helper class/structure for storing data to be printed to file
	 */
	public class YearlyViewData {
		
		long absoluteDays = 0;
		int totalFixedAndClosedIssues = 0;
		int newIssues = 0;
		int closedIssues = 0;
		long daysOpen = 0;
		
		@Override
		public String toString()
		{
			return "Absolute days: " + absoluteDays + " - Total active: " + totalFixedAndClosedIssues+" - New: "+newIssues+" - Close: "+
					closedIssues+" - Avg. days open:  "+daysOpen;
		}
	}
}
